﻿/*
 * 由SharpDevelop创建。
 * 用户： Admin
 * 日期: 2025/5/4
 * 时间: 17:33
 * 
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace BDSCSBox
{
	/// <summary>
	/// Description of JobControl.
	/// </summary>
	// 设置为子进程
	public class JobControl
	{
		public enum JobObjectInfoType
		{
			AssociateCompletionPortInformation = 7,
			BasicLimitInformation = 2,
			BasicUIRestrictions = 4,
			EndOfJobTimeInformation = 6,
			ExtendedLimitInformation = 9,
			SecurityLimitInformation = 5,
			GroupInformation = 11
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct SECURITY_ATTRIBUTES
		{
			public int nLength;
			public IntPtr lpSecurityDescriptor;
			public int bInheritHandle;
		}

		[StructLayout(LayoutKind.Sequential)]
		struct JOBOBJECT_BASIC_LIMIT_INFORMATION
		{
			public Int64 PerProcessUserTimeLimit;
			public Int64 PerJobUserTimeLimit;
			public Int16 LimitFlags;
			public UInt32 MinimumWorkingSetSize;
			public UInt32 MaximumWorkingSetSize;
			public Int16 ActiveProcessLimit;
			public Int64 Affinity;
			public Int16 PriorityClass;
			public Int16 SchedulingClass;
		}

		[StructLayout(LayoutKind.Sequential)]
		struct IO_COUNTERS
		{
			public UInt64 ReadOperationCount;
			public UInt64 WriteOperationCount;
			public UInt64 OtherOperationCount;
			public UInt64 ReadTransferCount;
			public UInt64 WriteTransferCount;
			public UInt64 OtherTransferCount;
		}

		[StructLayout(LayoutKind.Sequential)]
		struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
		{
			public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
			public IO_COUNTERS IoInfo;
			public UInt32 ProcessMemoryLimit;
			public UInt32 JobMemoryLimit;
			public UInt32 PeakProcessMemoryUsed;
			public UInt32 PeakJobMemoryUsed;
		}


		/// <summary>
		/// 创建作业对象
		/// </summary>
		/// <param name="lpJobAttributes">该作业的安全描述符</param>
		/// <param name="name">作业名字</param>
		/// <returns></returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
		static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string name);


		/// <summary>
		/// 将进程注册为作业对象进程
		/// </summary>
		/// <param name="job">作业对象句柄</param>
		/// <param name="process">进程句柄</param>
		/// <returns></returns>
		[DllImport("kernel32.dll", SetLastError = true)]
		static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);

		/// <summary>
		/// 设置作业对象限制
		/// </summary>
		/// <param name="hJob">标识要限制的作业   </param>
		/// <param name="infoType">枚举类型，用于指明要使用的限制类型</param>
		/// <param name="lpJobObjectInfo">包含限制设置值的数据结构的地址</param>
		/// <param name="cbJobObjectInfoLength">指明第三个参数的大小</param>
		/// <returns></returns>
		[DllImport("kernel32.dll")]
		static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
		
		const System.String job_name = "BDSCSBOX_mybdsJob";
		// private System.UInt32 job_ptr = 0;
		private System.IntPtr job_handle = System.IntPtr.Zero;
		/// <summary>
		/// 构造函数，声明作业对象，限制作业对象。
		/// </summary>
		public JobControl()
		{
			job_handle = CreateJobObject(System.IntPtr.Zero, job_name);
			JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
			info.LimitFlags = 0x2000;
			JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
			extendedInfo.BasicLimitInformation = info;
			//Design by LeventureQys
			int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
			IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
			Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

			if (!SetInformationJobObject(job_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
				throw new Exception(string.Format("Unable to set information.  Error: {0}", Marshal.GetLastWin32Error()));
		}


		/// <summary>
		/// 为该dll注册子进程，当主程序崩溃的时候，子进程一样退出
		/// </summary>
		/// <param name="added_process"></param>
		/// <returns></returns>
		public bool AddProcess(Process added_process)
		{
			System.IntPtr handle = System.IntPtr.Zero;
			handle = added_process.Handle;
			return AssignProcessToJobObject(job_handle, handle);
		}
	}
}
